Skip to content

refactor: env management#738

Merged
magne4000 merged 18 commits into
mainfrom
magne4000/env
May 27, 2026
Merged

refactor: env management#738
magne4000 merged 18 commits into
mainfrom
magne4000/env

Conversation

@magne4000

@magne4000 magne4000 commented May 27, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Centralized, declarative environment registry with per-sink overrides, grouping, and secret dev/test sourcing.
    • Helpers to render environment outputs for dotenv, Docker Compose, Dockerfile, and Cloudflare Wrangler.
  • Refactor

    • Moved env declarations into boilerplate configs and removed many per-boilerplate env transformers.
    • Build/CLI now aggregate and pass the unified env registry through transform operations.
  • Tests

    • Added Vitest suites covering dotenv, compose, and Wrangler env generation.
  • Chores

    • Added test scripts/dev deps for env-related packages and updated workspace config.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f2e14331-4ebb-4a60-b64c-9fd51f005957

📥 Commits

Reviewing files that changed from the base of the PR and between e147df6 and 1ce2abe.

📒 Files selected for processing (1)
  • boilerplates/sentry/bati.config.ts

📝 Walkthrough

Walkthrough

The PR centralizes environment variable definitions by introducing an EnvRegistry. Boilerplate configs declare env vars via env(); the CLI aggregates registries and passes them into build. Sink-specific renderers (renderDotenv, wranglerEnv, composeEnvEntries, serverEnvDefaults) generate dotenv, Wrangler, Docker Compose, and Dockerfile outputs. Former per-boilerplate $.env.ts transformers were removed.

Changes

Environment Registry and Rendering Architecture

Layer / File(s) Summary
Core env-registry types and helpers
packages/core/src/env-registry.ts, packages/core/src/types.ts
EnvVarDef defines scope (secret/server-default/public), sink overrides, grouping, and devValueFrom. Helpers isServerVar, committedValue, and secretDevValue classify vars and resolve values per sink.
Boilerplate env declarations
boilerplates/auth0/bati.config.ts, boilerplates/sentry/bati.config.ts, boilerplates/google-analytics/bati.config.ts, boilerplates/prisma/bati.config.ts, boilerplates/shared-db/bati.config.ts
Each boilerplate adds an env() factory returning variable definitions (Auth0 secrets grouped under auth0, Sentry secret+public pair, GA public var, Prisma DATABASE_URL server-default, shared-db conditional DATABASE_URL).
Unified dotenv rendering
boilerplates/shared/env.ts, boilerplates/shared/files/$.env.ts
renderDotenv(registry, meta) emits .env content by filtering entries by scope and hasDotEnvSecrets, quoting defaults, writing empty secret values when appropriate, and formatting multiline comments. Replaces per-boilerplate dotenv transformers.
Shared package test and config
boilerplates/shared/env.spec.ts, boilerplates/shared/package.json
Adds vitest test suite for renderDotenv, deterministic env isolation, and test script/devDependency updates.
Cloudflare Wrangler rendering
boilerplates/cloudflare/env.ts, boilerplates/cloudflare/files/$wrangler.jsonc.ts, boilerplates/cloudflare/env.spec.ts
wranglerEnv(registry) builds wrangler.vars from server vars using secret dev/test values or committed wrangler defaults. New transformer injects overrides into wrangler.jsonc; tests verify secret-empty defaults and dev/test injection.
Docker Compose environment helpers
boilerplates/docker-compose/env.ts, boilerplates/docker-compose/env.spec.ts
composeEnvEntries(registry) formats docker-compose environment entries (${KEY} for secrets, ${KEY:-<default>} for others). serverEnvDefaults(registry) groups Dockerfile ENV defaults by feature and emits DockerfileEnvGroup records. Tests validate formats and grouping.
Docker Compose template wiring
boilerplates/docker-compose/files/$docker-compose.yml.ts, boilerplates/docker-compose/files/$Dockerfile.ts, boilerplates/docker-compose/files/docker-compose.yml
New getDockerCompose() reads the template and injects composed env entries via setComposeEnvironment(). Runner-stage Dockerfile now iterates serverEnvDefaults(props.env) instead of in-file hard-coded defaults. Compose template environment list trimmed to base vars (NODE_ENV, PORT).
Remove boilerplate-specific transformers
boilerplates/auth0/files/$.env.ts, boilerplates/google-analytics/files/$.env.ts, boilerplates/drizzle/files/$.env.ts, boilerplates/kysely/files/$.env.ts, boilerplates/prisma/files/$.env.ts, boilerplates/sentry/files/$.env.ts, boilerplates/sqlite/files/$.env.ts, packages/core/src/utils/env.ts
Deletes prior per-boilerplate $.env.ts transformers and the appendToEnv utility; env generation is centralized through the registry renderers.
Build and CLI integration
packages/build/src/index.ts, packages/build/src/operations/transform.ts, packages/cli/index.ts
main() accepts optional env?: EnvRegistry and forwards it into executeOperationTransform(), which passes env into transformer invocations. CLI aggregates config.env?.(meta) from selected boilerplates and supplies the merged registry to the build exec call.
Config schema and type updates
packages/core/src/config.ts, packages/features/src/helpers.ts
BatiConfig adds optional env?: EnvRegistryFactory. TransformerProps now expects env: EnvRegistry. BatiSet.hasDotEnvSecrets getter added to control dotenv-secret inclusion (false for Cloudflare, true otherwise).
YAML, exports, and format updates
packages/core/src/parse/yaml.ts, packages/core/src/index.ts, packages/core/src/format.ts
Adds setComposeEnvironment() to append env entries into docker-compose YAML. Core barrel exports now include env-registry.js and drop utils/env. Prettier setup changed to route TypeScript parsing to Babel's babel-ts via a custom plugin. Tests added for YAML helper.
Test infrastructure and workspace
boilerplates/cloudflare/package.json, boilerplates/cloudflare/tsconfig.json, boilerplates/docker-compose/package.json, packages/tests-utils/src/index.ts, pnpm-workspace.yaml
Adds vitest and test scripts to affected boilerplates; Cloudflare tsconfig includes node types. Reorders a re-export in test-utils. Disables Nx verifyDepsBeforeRun in workspace settings.

Possibly related PRs

  • vikejs/bati#734: Previous PR introduced docker-compose Dockerfile generation with hard-coded DATABASE_URL, Auth0, and Sentry defaults; this PR refactors that logic to pull defaults from centralized EnvRegistry via serverEnvDefaults().
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: env management' clearly describes the main objective of this changeset, which involves a comprehensive refactoring of how environment variables are managed across boilerplates and the build system.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

magne4000 and others added 5 commits May 27, 2026 11:31
Introduce a single source of truth for environment variables. Each feature
will declare the vars it needs once (EnvVarDef[]) on its BatiConfig, and the
`.env`, docker-compose `environment:` and Dockerfile `ENV` sinks are derived
from the merged registry via renderDotenv / composeEnvEntries / serverEnvDefaults.

Pure addition — nothing is wired to consume `config.env` yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aggregate each selected boilerplate's `config.env` into one registry in the
CLI, pass it through exec() -> build main() -> executeOperationTransform, and
expose it on TransformerProps.env. No consumer yet; output is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Declare each feature's env vars on its bati.config (auth0, sentry, sqlite,
drizzle, kysely, prisma, google-analytics) and generate the whole .env from
one shared transformer (renderDotenv) instead of seven per-feature $.env.ts.

Behaviour is preserved: same keys/values/comments/order, the cloudflare and
D1 exclusions become declarative `when` predicates, and projects with no env
vars still get no .env file. Adds unit tests for the three sink emitters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the hardcoded auth0/sentry/database env lines (and their # BATI
conditional comments) in the docker-compose.yml skeleton with a
$docker-compose.yml.ts transform that injects services.app.environment from
the merged registry via the new setComposeEnvironment helper. The boilerplate
no longer knows about other features' vars.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…stry

Replace the hardcoded auth0/sentry/database .when(...).env(...) blocks in the
runner stage with a loop over serverEnvDefaults(props.env, meta). The runner
stage no longer references specific features; adding a feature with env vars
needs no change here. Drizzle's build-time DATABASE_URL (for drizzle:generate)
stays as feature-specific build wiring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
magne4000 and others added 12 commits May 27, 2026 12:13
Core now owns only the env-registry data model (types + envVarApplies) and the
generic primitives (appendToEnv, setComposeEnvironment). The per-sink rendering
policy lives with the boilerplate that owns the sink:

- shared/env.ts          -> renderDotenv          (.env)
- docker-compose/env.ts  -> composeEnvEntries,
                            serverEnvDefaults      (compose + Dockerfile)

The $ transformers import these via ../env (relative imports are allowed in
$-files). Renderer unit tests move next to the code (shared/docker-compose gain
a vitest test script + devDeps). Generated .env/compose/Dockerfile output is
unchanged (verified by generation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "empty secret" assertions read process.env.TEST_AUTH0_CLIENT_ID /
TEST_SENTRY_DSN via devValueFrom; when those are set in the shell or .env.test
the secret renders non-empty and the test fails. Clear them in beforeEach and
restore in afterEach so the suite is hermetic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@magne4000 magne4000 marked this pull request as ready for review May 27, 2026 14:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
boilerplates/shared/env.spec.ts (1)

7-9: ⚡ Quick win

Replace as never[] with the required BATI.If casting style.

This cast bypasses type intent and doesn’t follow the boilerplate casting convention required in this repo.

Use this read-only check to confirm remaining violations in boilerplate TS files:

#!/bin/bash
rg -nP --type=ts '\bas\s+never\[\]' boilerplates
rg -nP --type=ts 'BATI\.If<' boilerplates

As per coding guidelines boilerplates/**/*.ts: Use BATI.If with conditional type definition syntax for type casting in boilerplate TypeScript files: BATI.If<{'BATI.has("feature")': Type; _: FallbackType;}>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@boilerplates/shared/env.spec.ts` around lines 7 - 9, In the meta function,
replace the unsafe cast "as never[]" on the flags argument passed to new BatiSet
with the repo-standard BATI.If conditional type cast; update the call in
function meta(...flags: string[]): VikeMeta so that the flags parameter uses
BATI.If<{ 'BATI.has("feature")': DesiredType; _: FallbackType; }> (per
boilerplate convention) instead of as never[], ensuring you reference the
BatiSet constructor and BATI.If typing to satisfy the boilerplate TS casting
rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@boilerplates/sentry/bati.config.ts`:
- Line 11: Update the user-facing comment strings that mistakenly say "DNS" to
"DSN": find the config entries where the property comment equals "Sentry DNS.
Used for Error Reporting on the Server" (and the second occurrence at "Sentry
DNS. Used for Error Reporting on the Client") and change "DNS" to "DSN" so they
read "Sentry DSN. Used for Error Reporting on the Server/Client" respectively;
keep the rest of the comment text unchanged.

In `@boilerplates/shared-db/bati.config.ts`:
- Around line 9-21: The env generator in bati.config.ts currently emits a
DATABASE_URL entry unless meta.BATI.hasD1 is true, causing a duplicate when
Prisma also declares DATABASE_URL; update the condition in the env: (meta) =>
... logic to skip emitting the DATABASE_URL object when Prisma is enabled (e.g.
check meta.BATI.hasPrisma or the appropriate Prisma flag alongside
meta.BATI.hasD1) so the DATABASE_URL key is only added when neither D1 nor
Prisma are selected.

In `@packages/core/src/format.ts`:
- Line 1: The file registers Prettier standalone + plugin and a custom
typescriptViaBabel parser (parser "babel-ts") inside formatCode, causing TS/TSX
to be formatted by Prettier instead of the monorepo's Biome formatter policy;
remove the Prettier-specific wiring (imports of Prettier Plugin/standalone and
the typescriptViaBabel parser registration) and change formatCode to call the
monorepo Biome formatting API for TS/TSX files (use the Biome formatter
policy/formatter entrypoint used elsewhere in the repo), ensuring TypeScript/TSX
are routed to Biome rather than invoking Prettier and delete any references to
parser "babel-ts" and the custom typescriptViaBabel symbol.

---

Nitpick comments:
In `@boilerplates/shared/env.spec.ts`:
- Around line 7-9: In the meta function, replace the unsafe cast "as never[]" on
the flags argument passed to new BatiSet with the repo-standard BATI.If
conditional type cast; update the call in function meta(...flags: string[]):
VikeMeta so that the flags parameter uses BATI.If<{ 'BATI.has("feature")':
DesiredType; _: FallbackType; }> (per boilerplate convention) instead of as
never[], ensuring you reference the BatiSet constructor and BATI.If typing to
satisfy the boilerplate TS casting rule.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d6e075a3-a2de-4a31-9094-b77a981c9ded

📥 Commits

Reviewing files that changed from the base of the PR and between ab14f35 and e147df6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (42)
  • boilerplates/auth0/bati.config.ts
  • boilerplates/auth0/files/$.env.ts
  • boilerplates/auth0/files/$wrangler.jsonc.ts
  • boilerplates/cloudflare/env.spec.ts
  • boilerplates/cloudflare/env.ts
  • boilerplates/cloudflare/files/$wrangler.jsonc.ts
  • boilerplates/cloudflare/package.json
  • boilerplates/cloudflare/tsconfig.json
  • boilerplates/docker-compose/env.spec.ts
  • boilerplates/docker-compose/env.ts
  • boilerplates/docker-compose/files/$Dockerfile.ts
  • boilerplates/docker-compose/files/$docker-compose.yml.ts
  • boilerplates/docker-compose/files/docker-compose.yml
  • boilerplates/docker-compose/package.json
  • boilerplates/drizzle/files/$.env.ts
  • boilerplates/google-analytics/bati.config.ts
  • boilerplates/google-analytics/files/$.env.ts
  • boilerplates/kysely/files/$.env.ts
  • boilerplates/prisma/bati.config.ts
  • boilerplates/prisma/files/$.env.ts
  • boilerplates/sentry/bati.config.ts
  • boilerplates/sentry/files/$.env.ts
  • boilerplates/shared-db/bati.config.ts
  • boilerplates/shared/env.spec.ts
  • boilerplates/shared/env.ts
  • boilerplates/shared/files/$.env.ts
  • boilerplates/shared/package.json
  • boilerplates/sqlite/files/$.env.ts
  • packages/build/src/index.ts
  • packages/build/src/operations/transform.ts
  • packages/cli/index.ts
  • packages/core/src/config.ts
  • packages/core/src/env-registry.ts
  • packages/core/src/format.ts
  • packages/core/src/index.ts
  • packages/core/src/parse/yaml.ts
  • packages/core/src/types.ts
  • packages/core/src/utils/env.ts
  • packages/core/tests/transform-yaml.spec.ts
  • packages/features/src/helpers.ts
  • packages/tests-utils/src/index.ts
  • pnpm-workspace.yaml
💤 Files with no reviewable changes (10)
  • boilerplates/kysely/files/$.env.ts
  • boilerplates/prisma/files/$.env.ts
  • packages/core/src/utils/env.ts
  • boilerplates/sentry/files/$.env.ts
  • boilerplates/google-analytics/files/$.env.ts
  • boilerplates/sqlite/files/$.env.ts
  • boilerplates/auth0/files/$wrangler.jsonc.ts
  • boilerplates/drizzle/files/$.env.ts
  • boilerplates/docker-compose/files/docker-compose.yml
  • boilerplates/auth0/files/$.env.ts

Comment thread boilerplates/sentry/bati.config.ts Outdated
Comment thread boilerplates/shared-db/bati.config.ts
Comment thread packages/core/src/format.ts
@magne4000 magne4000 merged commit de2e0ee into main May 27, 2026
3 of 6 checks passed
@magne4000 magne4000 deleted the magne4000/env branch May 27, 2026 15:01
This was referenced May 28, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant